#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
代码加密系统 - 实现应用程序关键代码的加密功能
通过多种加密技术保护核心算法和敏感逻辑不被逆向工程
"""
import os
import sys
import base64
import json
import zlib
import hashlib
import marshal
import types
import importlib.util
import tempfile
import shutil
from datetime import datetime
import threading
import inspect

# 导入项目模块
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from utils import Logger
from utils.security_utils import SecurityUtils
from utils.file_utils import FileUtils

class CodeEncryptor:
    """代码加密系统核心类"""
    def __init__(self):
        """初始化代码加密系统"""
        self.security_utils = SecurityUtils()
        self.file_utils = FileUtils()
        
        # 线程锁，确保加密操作的线程安全
        self.encrypt_lock = threading.Lock()
        
        # 支持加密的文件类型
        self.supported_file_types = ['.py']
        
        # 加密配置
        self.encryption_config = {
            "enable_encryption": True,
            "encryption_level": "medium",  # low, medium, high
            "compress_before_encrypt": True,
            "obfuscate_variables": True,
            "encrypt_strings": True,
            "exclude_dirs": ["tests", "__pycache__", ".git", "docs"],
            "exclude_files": ["__init__.py", "setup.py"]
        }
        
        Logger.log_info("代码加密系统初始化完成")
    
    def encrypt_file(self, file_path, output_path=None, config_overrides=None):
        """加密单个Python文件
        
        参数:
            file_path: 要加密的文件路径
            output_path: 加密后的输出文件路径，默认为原文件路径加上.encrypted后缀
            config_overrides: 加密配置覆盖
        
        返回:
            tuple: (是否成功, 消息, 加密后的文件路径)
        """
        try:
            with self.encrypt_lock:
                # 检查文件是否存在
                if not os.path.exists(file_path):
                    error_msg = f"要加密的文件不存在: {file_path}"
                    Logger.log_error(error_msg)
                    return False, error_msg, None
                
                # 检查文件类型是否支持加密
                _, ext = os.path.splitext(file_path)
                if ext.lower() not in self.supported_file_types:
                    error_msg = f"不支持加密的文件类型: {ext}"
                    Logger.log_error(error_msg)
                    return False, error_msg, None
                
                # 检查是否在排除列表中
                if self._is_excluded(file_path):
                    Logger.log_info(f"文件在排除列表中，跳过加密: {file_path}")
                    return True, "文件在排除列表中，跳过加密", None
                
                # 应用配置覆盖
                config = self.encryption_config.copy()
                if config_overrides:
                    config.update(config_overrides)
                
                # 如果未启用加密，直接返回成功
                if not config["enable_encryption"]:
                    Logger.log_info(f"加密功能未启用，跳过加密: {file_path}")
                    return True, "加密功能未启用，跳过加密", None
                
                # 确定输出路径
                if output_path is None:
                    output_path = f"{file_path}.encrypted"
                
                # 确保输出目录存在
                os.makedirs(os.path.dirname(output_path), exist_ok=True)
                
                # 读取文件内容
                with open(file_path, 'r', encoding='utf-8') as f:
                    source_code = f.read()
                
                # 根据加密级别执行不同的加密操作
                encrypted_code = self._encrypt_code(source_code, config["encryption_level"])
                
                # 获取加载器代码模板
                loader_template = self._get_loader_template(config["encryption_level"])
                
                # 组合加载器模板和加密后的代码
                final_code = loader_template.replace('ENCRYPTED_CODE_PLACEHOLDER', encrypted_code)
                
                # 写入加密后的文件
                with open(output_path, 'w', encoding='utf-8') as f:
                    f.write(final_code)
                
                Logger.log_info(f"文件加密成功: {file_path} -> {output_path}")
                return True, f"文件加密成功", output_path
        except Exception as e:
            error_msg = f"文件加密失败: {str(e)}"
            Logger.log_error(error_msg)
            return False, error_msg, None
    
    def _is_excluded(self, file_path):
        """检查文件是否在排除列表中"""
        # 检查文件是否在排除文件列表中
        file_name = os.path.basename(file_path)
        if file_name in self.encryption_config["exclude_files"]:
            return True
        
        # 检查文件所在目录是否在排除目录列表中
        for exclude_dir in self.encryption_config["exclude_dirs"]:
            if exclude_dir in file_path:
                return True
        
        return False
    
    def _encrypt_code(self, source_code, level):
        """加密代码内容
        
        参数:
            source_code: 源代码字符串
            level: 加密级别 (low, medium, high)
        
        返回:
            str: 加密后的代码
        """
        try:
            # 将源代码转换为字节
            data = source_code.encode('utf-8')
            
            # 如果启用了压缩，先压缩数据
            if self.encryption_config["compress_before_encrypt"]:
                data = zlib.compress(data)
            
            # 根据不同的加密级别执行不同的加密操作
            if level == "high":
                # 高级加密：多层加密和混淆
                return self._advanced_encrypt(data)
            elif level == "medium":
                # 中级加密：加密和简单混淆
                return self._medium_encrypt(data)
            else:
                # 低级加密：基本加密
                return self._basic_encrypt(data)
        except Exception as e:
            Logger.log_error(f"代码加密过程出错: {str(e)}")
            raise
    
    def _advanced_encrypt(self, data):
        """高级加密算法实现"""
        # 实现多层加密和混淆
        try:
            # 1. 第一层加密：使用安全工具的加密方法
            key1 = self.security_utils.generate_encryption_key()
            encrypted1 = self.security_utils.encrypt_data(data, key1)
            
            # 2. 再次加密密钥和密文
            combined_data = encrypted1 + key1
            key2 = self.security_utils.generate_encryption_key()
            encrypted2 = self.security_utils.encrypt_data(combined_data, key2)
            
            # 3. 返回最终加密结果和用于解密的辅助数据
            # 实际项目中应使用更复杂的密钥管理策略
            return encrypted2 + key2[:8]  # 仅存储部分密钥作为示例
        except Exception as e:
            Logger.log_error(f"高级加密过程出错: {str(e)}")
            raise
    
    def _medium_encrypt(self, data):
        """中级加密算法实现"""
        # 实现中级加密
        try:
            # 1. 使用安全工具的加密方法
            key = self.security_utils.generate_encryption_key()
            encrypted = self.security_utils.encrypt_data(data, key)
            
            # 2. 返回加密结果和简化的密钥信息
            return encrypted + key[:4]  # 仅存储部分密钥作为示例
        except Exception as e:
            Logger.log_error(f"中级加密过程出错: {str(e)}")
            raise
    
    def _basic_encrypt(self, data):
        """低级加密算法实现"""
        # 实现基本加密
        try:
            # 简单的base64编码作为低级加密
            return base64.b64encode(data).decode('utf-8')
        except Exception as e:
            Logger.log_error(f"低级加密过程出错: {str(e)}")
            raise
    
    def _get_loader_template(self, level):
        """获取加载器代码模板"""
        # 根据不同的加密级别返回不同的加载器代码
        if level == "high":
            return '''#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""高级加密代码加载器"""
import os
import base64
import zlib
import marshal
exec(compile(marshal.loads(zlib.decompress(base64.b64decode('eJx1kM9qwkAUxr/9KqIUiw+KQ4Q84DvF7E1gE9JkA8t2IcXgOq2cZ2VnQfT/
    9i7sZfz8a3n3O4hH1T0xO8UQyJQJEZcE+hKx0+I1iN1WnHq25g+e9L2t6K5'))))))'''
        elif level == "medium":
            return '''#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""中级加密代码加载器"""
import os
import base64
import zlib
exec(zlib.decompress(base64.b64decode('eJx1kM9qwkAUxr/9KqIUiw+KQ4Q84DvF7E1gE9JkA8t2IcXgOq2cZ2VnQfT/
    9i7sZfz8a3n3O4hH1T0xO8UQyJQJEZcE+hKx0+I1iN1WnHq25g+e9L2t6K5'))))'''
        else:
            return '''#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""低级加密代码加载器"""
import os
import base64
exec(base64.b64decode('eJx1kM9qwkAUxr/9KqIUiw+KQ4Q84DvF7E1gE9JkA8t2IcXgOq2cZ2VnQfT/
    9i7sZfz8a3n3O4hH1T0xO8UQyJQJEZcE+hKx0+I1iN1WnHq25g+e9L2t6K5'))))'''

# 简单的测试函数，仅在直接运行模块时执行
if __name__ == "__main__":
    encryptor = CodeEncryptor()
    Logger.log_info("代码加密系统模块测试")
    # 这里可以添加测试代码